#include "ScoreboardTest.h"
#include "Scoreboard.h"
#include "Timeout.h"

#include <stdexcept>

CPPUNIT_TEST_SUITE_REGISTRATION(ScoreboardTest);

void ScoreboardTest::setUp() {
	START_TIMEOUT(1000);
}

void ScoreboardTest::tearDown() {
	STOP_TIMEOUT();
}

void ScoreboardTest::testEmptyScoreboard() {
	ostringstream expected;
	expected << "The scoreboard is empty." << endl;

	Scoreboard scoreboard;
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}

void ScoreboardTest::testAddScoreWhenScoreboardIsEmpty() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 5 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 5);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}
void ScoreboardTest::testAddScoreWhenScoreboardIsNotFull() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 1 moves" << endl
		<< "2. player2 --> 2 moves" << endl
		<< "3. player3 --> 3 moves" << endl
		<< "4. player4 --> 4 moves" << endl
		<< "5. player5 --> 5 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);

	scoreboard.addScore("player5", 5);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}
void ScoreboardTest::testAddTopScoreWhenScoreboardIsFull() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 1 moves" << endl
		<< "2. player2 --> 2 moves" << endl
		<< "3. player3 --> 3 moves" << endl
		<< "4. player4 --> 4 moves" << endl
		<< "5. player6 --> 5 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 6);

	scoreboard.addScore("player6", 5);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}
void ScoreboardTest::testAddNontopScoreWhenScoreboardIsFull() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 1 moves" << endl
		<< "2. player2 --> 2 moves" << endl
		<< "3. player3 --> 3 moves" << endl
		<< "4. player4 --> 4 moves" << endl
		<< "5. player5 --> 5 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 5);

	scoreboard.addScore("player6", 6);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}

void ScoreboardTest::testAddScoreWhenScoreboardIsFullAndScoreIsSameAsTheLastOne() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 1 moves" << endl
		<< "2. player2 --> 2 moves" << endl
		<< "3. player3 --> 3 moves" << endl
		<< "4. player4 --> 4 moves" << endl
		<< "5. player5 --> 5 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 5);

	scoreboard.addScore("player6", 5);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}

void ScoreboardTest::testSortSameScores() {
	ostringstream expected;
	expected << "Scoreboard:" << endl
		<< "1. player1 --> 1 moves" << endl
		<< "2. player2 --> 2 moves" << endl
		<< "3. player3 --> 3 moves" << endl
		<< "4. player6 --> 3 moves" << endl
		<< "5. player4 --> 4 moves" << endl;

	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 5);

	scoreboard.addScore("player6", 3);
	ostringstream actual;
	actual << scoreboard;

	CPPUNIT_ASSERT_EQUAL(expected.str(), actual.str());
}

void ScoreboardTest::testIsTopScoreWhenScoreboardIsEmpty() {
	Scoreboard scoreboard;
	CPPUNIT_ASSERT(scoreboard.isTopScore(5));
}

void ScoreboardTest::testIsTopScoreWhenScoreboardIsNotFull() {
	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	CPPUNIT_ASSERT(scoreboard.isTopScore(5));
}

void ScoreboardTest::testIsTopScoreWhenScoreboardIsFullAndScoreIsTop() {
	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 6);
	CPPUNIT_ASSERT(scoreboard.isTopScore(5));
}

void ScoreboardTest::testIsTopScoreWhenScoreboardIsFullAndScoreIsNotTop() {
	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 5);
	CPPUNIT_ASSERT(!scoreboard.isTopScore(6));
}

void ScoreboardTest::testIsTopScoreWhenScoreboardIsFullAndScoreIsSameAsTheLastOne() {
	Scoreboard scoreboard;
	scoreboard.addScore("player1", 1);
	scoreboard.addScore("player2", 2);
	scoreboard.addScore("player3", 3);
	scoreboard.addScore("player4", 4);
	scoreboard.addScore("player5", 5);
	CPPUNIT_ASSERT(!scoreboard.isTopScore(5));
}

void ScoreboardTest::testAddScoreThrowsExceptionWhenMovesAreLessThanNull() {
	Scoreboard scoreboard;
	CPPUNIT_ASSERT_THROW(scoreboard.addScore("player1", -1), invalid_argument);
}

void ScoreboardTest::testAddScoreThrowsExceptionWhenPlayerNameIsInvalid() {
	Scoreboard scoreboard;
	CPPUNIT_ASSERT_THROW(scoreboard.addScore("", 5), invalid_argument);
}

void ScoreboardTest::testIsTopScoreThrowsExceptionWhenMovesAreLessThanNull() {
	Scoreboard scoreboard;
	CPPUNIT_ASSERT_THROW(scoreboard.isTopScore(-1), invalid_argument);
}

